package net.trevize.datasetexplorer;

import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Iterator;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;

import net.infonode.docking.DockingWindow;
import net.infonode.docking.RootWindow;
import net.infonode.docking.SplitWindow;
import net.infonode.docking.TabWindow;
import net.infonode.docking.View;
import net.infonode.docking.drop.DropFilter;
import net.infonode.docking.drop.DropInfo;
import net.infonode.docking.drop.InteriorDropInfo;
import net.infonode.docking.properties.RootWindowProperties;
import net.infonode.docking.theme.DockingWindowsTheme;
import net.infonode.docking.util.DockingUtil;
import net.infonode.docking.util.ViewMap;
import net.infonode.util.Direction;
import net.trevize.IIDF.gui.ExploreIIDFPanel;
import net.trevize.datasetexplorer.dialogs.AboutDialog;
import net.trevize.datasetexplorer.dialogs.LoadDatasetDialog;
import net.trevize.galatee.Galatee;

import org.java.plugin.ObjectFactory;
import org.java.plugin.PluginLifecycleException;
import org.java.plugin.PluginManager;
import org.java.plugin.PluginManager.PluginLocation;
import org.java.plugin.registry.PluginDescriptor;
import org.java.plugin.standard.StandardPluginLocation;

public class DatasetExplorer implements ActionListener {

	public static void main(String[] args) {
		// setting the look and feel
		if (System.getProperty("os.name").toLowerCase().contains("windows")) {
			try {
				UIManager
						.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (UnsupportedLookAndFeelException e) {
				e.printStackTrace();
			}
		} else {
			try {
				UIManager
						.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (UnsupportedLookAndFeelException e) {
				e.printStackTrace();
			}
		}

		new DatasetExplorer();
	}

	public static final String ACTION_COMMAND_LOAD_DATASET = "ACTION_COMMAND_LOAD_DATASET";
	public static final String ACTION_COMMAND_ABOUT = "ACTION_COMMAND_ABOUT";

	// Infonode components
	private RootWindow root_window;
	private ViewMap view_map;
	private SplitWindow main_split_window;
	private TabWindow galatee_tabs_window;
	private View fs_explorer_window;

	// classic SWING components
	private JFrame main_frame;
	private JPanel main_panel;
	private JPanel fs_explorer;
	private LoadDatasetDialog dialog_load_dataset;
	private AboutDialog dialog_about;

	private int num_of_fs_explorer_tabs;
	private int num_of_local_dataset_explorer_tabs;
	private int num_of_http_dataset_explorer_tabs;
	private int num_of_iidf_explorer_tabs;

	public DatasetExplorer() {
		init();

		loadPlugins();
	}

	private void init() {
		main_frame = new JFrame("DatasetExplorer");
		main_frame.setIconImage(Toolkit.getDefaultToolkit().getImage(
				DatasetExplorerProperties.getIcon_path_datasetexplorer()));

		main_panel = new JPanel();
		main_panel.setLayout(new BorderLayout());
		main_frame.getContentPane().add(main_panel);

		// setting the menu bar
		JMenuBar menu_bar = new JMenuBar();
		main_frame.setJMenuBar(menu_bar);
		JMenu menu_dataset = new JMenu("File");
		menu_bar.add(menu_dataset);

		// setting the menu bar
		JMenuItem menuitem_load_dataset = new JMenuItem("Load dataset");
		menuitem_load_dataset.setActionCommand(ACTION_COMMAND_LOAD_DATASET);
		menuitem_load_dataset.addActionListener(this);
		menu_dataset.add(menuitem_load_dataset);

		JMenu menu_help = new JMenu("Help");
		menu_bar.add(menu_help);

		JMenuItem menuitem_about = new JMenuItem("About");
		menuitem_about.setActionCommand(ACTION_COMMAND_ABOUT);
		menuitem_about.addActionListener(this);
		menu_help.add(menuitem_about);

		// preparing the infonode windows
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				view_map = new ViewMap();

				root_window = DockingUtil.createRootWindow(view_map, true);

				root_window.getRootWindowProperties().setRecursiveTabsEnabled(
						false);

				root_window.getRootWindowProperties()
						.getDockingWindowProperties().getDropFilterProperties()
						.setInteriorDropFilter(new DropFilter() {
							public boolean acceptDrop(DropInfo dropInfo) {
								InteriorDropInfo interiorDropInfo = (InteriorDropInfo) dropInfo;
								// If the drop window is a split window and the
								// drag window is a tab window, no drops are
								// allowed
								if (interiorDropInfo.getDropWindow() instanceof SplitWindow
										&& interiorDropInfo.getWindow() instanceof TabWindow)
									return false;
								return true;
							}
						});

				root_window.getRootWindowProperties()
						.getFloatingWindowProperties().setUseFrame(true);

				root_window.getRootWindowProperties().getTabWindowProperties()
						.getTabProperties().getTitledTabProperties()
						.setFocusMarkerEnabled(false);

				// removing the ugly border on the InfoNode default theme
				root_window.getRootWindowProperties().getWindowAreaProperties()
						.setBorder(new EmptyBorder(0, 0, 0, 0));

				root_window.getWindowBar(Direction.RIGHT).setEnabled(true);
				root_window.getWindowBar(Direction.RIGHT).setContentPanelSize(
						256);

				// add the root window to the main panel
				main_panel.add(root_window, BorderLayout.CENTER);

				// create the fs_tree_view
				fs_explorer = new FSExplorerPanel(DatasetExplorer.this);
				fs_explorer_window = new View("File Systems explorer", null,
						fs_explorer);
				view_map.addView(view_map.getViewCount(), fs_explorer_window);

				// setting the root window
				root_window.setWindow(fs_explorer_window);

				// configuring the windows
				fs_explorer_window.minimize();

				// set the Infonode theme
				try {
					setInfonodeTheme((DockingWindowsTheme) Class.forName(
							DatasetExplorerProperties
									.getDocking_windows_theme()).newInstance());
				} catch (InstantiationException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
			}
		});

		main_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Dimension screen_dim = Toolkit.getDefaultToolkit().getScreenSize();
		main_frame.setSize((int) (screen_dim.width * 10. / 12.),
				(int) (screen_dim.height * 10. / 12.));
		main_frame.setLocationRelativeTo(null);
		main_frame.setVisible(true);

		// adding the global key listener
		Toolkit.getDefaultToolkit().addAWTEventListener(
				new GlobalKeyListener(this), AWTEvent.KEY_EVENT_MASK);

		// preparing the dialogs
		dialog_about = new AboutDialog(main_panel);

		num_of_fs_explorer_tabs = 0;
		num_of_local_dataset_explorer_tabs = 0;
		num_of_http_dataset_explorer_tabs = 0;
		num_of_iidf_explorer_tabs = 0;
	}

	public void setInfonodeTheme(DockingWindowsTheme docking_windows_theme) {
		RootWindowProperties properties = new RootWindowProperties();

		// Set gradient theme. The theme properties object is the super object
		// of our properties object, which
		// means our property value settings will override the theme values
		properties.addSuperObject(docking_windows_theme
				.getRootWindowProperties());

		// Our properties object is the super object of the root window
		// properties object, so all property values of the
		// theme and in our property object will be used by the root window
		root_window.getRootWindowProperties().addSuperObject(properties);
	}

	private void loadPlugins() {
		// create a plugin manager.
		PluginManager pluginManager = ObjectFactory.newInstance()
				.createManager();

		// retrieve the plugin archives.
		File pluginsDir = new File("./plugins");
		File[] plugins = pluginsDir.listFiles(new FilenameFilter() {
			public boolean accept(File dir, String name) {
				return name.toLowerCase().endsWith(".zip");
			}
		});

		// if no plugins found we return.
		if (plugins == null) {
			return;
		}

		// get PluginLocation objects and publish the plugins.
		try {
			PluginLocation[] locations = new PluginLocation[plugins.length];

			for (int i = 0; i < plugins.length; i++) {
				locations[i] = StandardPluginLocation.create(plugins[i]);
			}

			pluginManager.publishPlugins(locations);
		} catch (Exception e) {
			e.printStackTrace();
		}

		// iterate over all the found plugins.
		Iterator<PluginDescriptor> it = pluginManager.getRegistry()
				.getPluginDescriptors().iterator();

		while (it.hasNext()) {
			PluginDescriptor p = (PluginDescriptor) it.next();
			try {
				DatasetExplorerPlugin de_plugin = (DatasetExplorerPlugin) pluginManager
						.getPlugin(p.getId());
				de_plugin.setDatasetExplorerObject(this);
				de_plugin.init();
			} catch (PluginLifecycleException e) {
				e.printStackTrace();
			}
		}
	}

	private void addViewToGalateeTabsWindow(View view) {
		view_map.addView(view_map.getViewCount(), view);

		if (root_window.getWindow() == null) {
			if (galatee_tabs_window == null) {
				galatee_tabs_window = new TabWindow(
						new DockingWindow[] { view });
				root_window.setWindow(galatee_tabs_window);
			} else {
				galatee_tabs_window.addTab(view);
				root_window.setWindow(galatee_tabs_window);
			}
		}

		else

		if (galatee_tabs_window == null) {
			galatee_tabs_window = new TabWindow(new DockingWindow[] { view });
			root_window.split(galatee_tabs_window, Direction.LEFT, 0.65f);
		}

		else {
			galatee_tabs_window.addTab(view);
		}
	}

	public void addGalateeTab(Galatee galatee, String title) {
		View view = new View(title, null, galatee);
		addViewToGalateeTabsWindow(view);
	}

	public void addFSExplorerTab(Galatee galatee, String filename) {
		String view_title = "FS Explorer #" + num_of_fs_explorer_tabs + " ["
				+ filename + "]";
		++num_of_fs_explorer_tabs;
		View view = new View(view_title, null, galatee);
		addViewToGalateeTabsWindow(view);
	}

	public void addLocalDatasetExplorerTab(Galatee galatee, String filename) {
		String view_title = "Local dataset explorer #"
				+ num_of_local_dataset_explorer_tabs + " [" + filename + "]";
		++num_of_local_dataset_explorer_tabs;
		View view = new View(view_title, null, galatee);
		addViewToGalateeTabsWindow(view);
	}

	public void addHTTPDatasetExplorerTab(Galatee galatee, String filename) {
		String view_title = "HTTP dataset explorer #"
				+ num_of_http_dataset_explorer_tabs + " [" + filename + "]";
		++num_of_http_dataset_explorer_tabs;
		View view = new View(view_title, null, galatee);
		addViewToGalateeTabsWindow(view);
	}

	public void addIIDFDatasetExplorerTab(ExploreIIDFPanel explore_iidf_panel,
			String iidf_path) {
		String view_title = "IIDF dataset explorer #"
				+ num_of_iidf_explorer_tabs + " [" + iidf_path + "]";
		++num_of_iidf_explorer_tabs;
		View view = new View(view_title, null, explore_iidf_panel);
		addViewToGalateeTabsWindow(view);
	}

	/***************************************************************************
	 * implementation of ActionListener.
	 **************************************************************************/

	@Override
	public void actionPerformed(ActionEvent e) {
		String action_command = e.getActionCommand();

		if (action_command.equals(ACTION_COMMAND_LOAD_DATASET)) {
			if (dialog_load_dataset == null) {
				dialog_load_dataset = new LoadDatasetDialog(this);
			}
			dialog_load_dataset.setVisible(true);
		}

		else

		if (action_command.equals(ACTION_COMMAND_ABOUT)) {
			dialog_about.setVisible(true);
		}

	}

	/***************************************************************************
	 * getters and setters.
	 **************************************************************************/

	public JFrame getFrame() {
		return main_frame;
	}

	public void setFrame(JFrame frame) {
		this.main_frame = frame;
	}

	public JPanel getMain_panel() {
		return main_panel;
	}

	public void setMain_panel(JPanel mainPanel) {
		main_panel = mainPanel;
	}

	public LoadDatasetDialog getDialog_load_dataset() {
		return dialog_load_dataset;
	}

	public void setDialog_load_dataset(LoadDatasetDialog dialogLoadDataset) {
		dialog_load_dataset = dialogLoadDataset;
	}

}
